#include "GnashManager.h"

GnashManager *GnashManager::mGnashManager=NULL;


GnashManager* GnashManager::getSingletonPtr( void )
{
	if ( !mGnashManager )
		{
			mGnashManager = new GnashManager();
		}

	return mGnashManager;
}

GnashManager::GnashManager() :
	root(0),
//	mRenderer(0),
	texture(0),
	overlay(0),
	panel(0),
	offscreenbuf(0),
	offscreenbuf_size(-1)
{
	vclock = new InterruptableVirtualClock(systemClock);
}

GnashManager::~GnashManager()
{
	delete vclock;
	delete root;

	gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
	dbglogfile.log("Gnash Closing....");
	dbglogfile.closeLog();

}


//void GnashUtils::setupGnash(std::auto_ptr<RunResources> runResources, InterruptableVirtualClock vclock, Renderer* renderer, boost::scoped_array<unsigned char> offscreenbuf, Ogre::Texture* gnashTex, OverlayContainer* panel, Overlay* overlay) {
void GnashManager::init()
{

	gnashInit();

	gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
	dbglogfile.removeLog();
	dbglogfile.setVerbosity(1);
	dbglogfile.setWriteDisk(true);
	dbglogfile.log("Gnash Loading....");

	const string url = "main.swf";
	const string pixelFormat = "BGRA32";
	const string guiXml = "gui.xml";

	runResources.reset(new RunResources(url));

	boost::shared_ptr<SWF::TagLoadersTable> loaders(new SWF::TagLoadersTable());
	addDefaultLoaders(*loaders);
	runResources->setTagLoaders(loaders);

	boost::shared_ptr<StreamProvider> streamProvider = boost::shared_ptr<StreamProvider>(new StreamProvider);

	runResources->setStreamProvider(streamProvider);


	FILE *stream;
	if ((stream = fopen(url.c_str(), "r")) == NULL)
		perror("fopen() error for SWF file");

	std::auto_ptr<IOChannel> in (noseek_fd_adapter::make_stream(fileno(stream)));
	boost::intrusive_ptr<movie_definition> moviedef =
	    MovieFactory::makeMovie(in, url, *runResources, false);
	if (!moviedef)
		throw GnashException("Could not load movie from "+url);

	root = new movie_root(*moviedef, *vclock, *runResources);
	if(!root)
		throw GnashException("Failed to get root movie");

	VM& vm = root->getVM();
	dbglogfile.log("SWF "+StringConverter::toString(vm.getSWFVersion()));

	unsigned width  = unsigned(moviedef->get_width_pixels());
	unsigned height = unsigned(moviedef->get_height_pixels());
	unsigned frames = unsigned(moviedef->get_frame_count());

	String str = StringConverter::toString(width) + "x" + StringConverter::toString(height);
	dbglogfile.log("SWF Movie reports size: "+str+" pixels");
	dbglogfile.log(StringConverter::toString(frames)+" frame(s) loaded....");


	try
		{
			mRendererAggBase.reset(create_Renderer_agg(pixelFormat.c_str()));
			dbglogfile.log("AGG Renderer Created, PixelFormat " + pixelFormat);

			std::cout << "AGG Renderer Created, PixelFormat " << pixelFormat << std::endl;
		}
	catch (std::bad_alloc &e)
		{
			std::cout << "Failed allocating AGG Renderer" << std::endl;
			gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
			dbglogfile.log("Gnash Closing....");
			dbglogfile.closeLog();

			throw GnashException("Failed to allocate AGG Renderer");
			return;
		}

//	if(!mRendererAggBase->initTestBuffer(width, height))
//		throw GnashException("Could not init Test Buffer");

	runResources->setRenderer(mRendererAggBase);


	unsigned int bpp = 32;
	int row_size = width*((bpp+7)/8);
	offscreenbuf_size = row_size * height ;

	try
		{
			offscreenbuf.reset(new unsigned char[offscreenbuf_size]);
			dbglogfile.log("Allocated " + StringConverter::toString(offscreenbuf_size) + " bytes offscreen buffer allocated");
		}
	catch (std::bad_alloc &e)
		{
			dbglogfile.log("Could not allocate: " + StringConverter::toString(offscreenbuf_size) + " bytes for offscreen buffer: "+
			               StringConverter::toString(e.what()));
			gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
			dbglogfile.log("Gnash Closing....");
			dbglogfile.closeLog();

			throw GnashException("Failed to allocate buffer");
			return;
		}



	mRendererAggBase->init_buffer(
	    offscreenbuf.get(),
	    offscreenbuf_size,
	    width,
	    height,
	    row_size
	);



	moviedef->completeLoad();
	moviedef->ensure_frame_loaded(moviedef->get_frame_count());


	fclose(stream);

	MovieClip::MovieVariables v;
	Movie* rm = root->init(moviedef.get(), v, v);
	if (!rm)
		{
			throw GnashException("Could not init movie");
			return;
		}

	std::cout << "Loaded " << rm->get_frame_count() << " frame(s)." << std::endl;

//	Global_as* gl = vm.getGlobal();
//	as_object* _r = root->getRootMovie().object();
//	// onLoadCallBack
//	_r->init_member("movieLoaded", gl->createFunction(GnashUtils::onLoadCallBack));
//	loadGui(guiXml);
	

	createOgreAssets(width, height);


//	root->notify_mouse_moved(0, 0);
	root->set_background_alpha(1);
	root->set_background_color(gnash::rgba(255,0,255,255));
//	root->set_background_alpha(0);


//	root->advanceMovie();
	root->advance();
	root->display();

}

void GnashManager::loadGui(string guiXml)
{
	VM& vm = root->getVM();
	as_environment env(VM::get());

	as_object* XmlParser = env.find_object("XmlParser");
	string_table::key key = vm.getStringTable().find("parse");

	FILE *xmlStream;
	if ((xmlStream = fopen(guiXml.c_str(), "r")) == NULL)
		perror("fopen() error for XML file");
	fseek (xmlStream , 0 , SEEK_END);
	int size = ftell (xmlStream);
	rewind (xmlStream);
	char* xml = (char*) malloc (sizeof(char)*size);
	fread(xml, 1, size, xmlStream);

	callMethod(XmlParser, key, xml);

	fclose(xmlStream);
	free (xml);
}

void GnashManager::createOgreAssets(int width, int height)
{
	texture = TextureManager::getSingleton().createManual(
	              "gnashTex",
	              ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
	              TEX_TYPE_2D,
	              width,
	              height,
	              0,
//	              PF_BYTE_BGRA,
	              PF_B8G8R8A8,
	              TU_DYNAMIC_WRITE_ONLY_DISCARDABLE
	          ).getPointer();


	GnashUtils::clearTexture(texture);

//	return;

	OverlayManager* olm = OverlayManager::getSingletonPtr();

	panel = static_cast<OverlayContainer*>(olm->createOverlayElement("Panel", "GnashPanel"));

	panel->setMetricsMode(Ogre::GMM_RELATIVE);
	panel->setPosition(0, 0);
	panel->setDimensions(1, 1);

	MaterialPtr material = MaterialManager::getSingleton().create("GnashTextureMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

	Ogre::TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState("gnashTex");
	tus->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
	tus->setTextureFiltering(TFO_NONE);
//	tus->setTextureFiltering(TFO_TRILINEAR);
	material->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);

//    material->getTechnique(0)->getPass(0)->setFragmentProgram("GrayScale_fp");
//    material->getTechnique(0)->getPass(0)->setFragmentProgram("Sepia_fp");
//    material->getTechnique(0)->getPass(0)->setFragmentProgram("ColorFilter_fp");
//	material->getTechnique(0)->getPass(0)->setFragmentProgram("DropShadow_fp");
//	material->getTechnique(0)->getPass(0)->setFragmentProgram("Scale2x_fp");
//    material->getTechnique(0)->getPass(0)->setFragmentProgram("Anim1_fp");

	panel->setMaterialName("GnashTextureMaterial");

	overlay = olm->create("GnashOverlay");
	overlay->add2D(panel);
	overlay->show();
}
